//#include "stdafx.h"
#include "cStringHelper.h"

#include <regex>
#include <iostream>
#include <cctype>
#include <sstream>
#include <memory.h>
#include <iomanip>

#ifdef _WIN32
#include <windows.h>
#endif // WIN32

namespace libcvos_vfr
{
	namespace Helper
	{

		bool isAllSpaces(const std::string& str)
		{
			for (char c : str) 
			{
				if (c != ' ') {
					return false;
				}
			}
			return true;
		}

		TOOL_SDK_API bool  DLL_SPEC Tool_ReplaceStringInStd(
			const char* strOrigin,
			const char* strToReplace, 
			const char* strNewChar,
			char* finalStringBuf, 
			int bufLen)
		{
			if(NULL == strOrigin || NULL == strToReplace || NULL == strNewChar || NULL == finalStringBuf || bufLen <= 0)
				return false;

			std::string strFinal = strOrigin;
			if (strFinal.empty())
			{
				return false;
			}

			if (isAllSpaces(strNewChar))
			{
				size_t pos = std::string::npos;

				// Search for the substring in string in a loop untill nothing is found
				while ((pos = strFinal.find(strToReplace)) != std::string::npos)
				{
					// If found then erase it from string
					strFinal.erase(pos, strlen(strToReplace));
				}
			}
			else
			{
				for (std::string::size_type pos(0); pos != std::string::npos; pos += strlen(strToReplace))
				{
					pos = strFinal.find(strToReplace, pos);
					if (pos != std::string::npos)
						strFinal.replace(pos, strlen(strToReplace), strNewChar);
					else
						break;
				}
			}
#ifdef _WIN32
			strncpy_s(finalStringBuf, bufLen, strFinal.c_str(), strFinal.length());
#else
			snprintf(finalStringBuf, bufLen, "%s", strFinal.c_str());
#endif
			return true;
		}

		TOOL_SDK_API bool DLL_SPEC Tool_CheckIfMatchExpressions(const char *targetCharSequence, const char *regularExpression)
		{
			if (NULL == targetCharSequence || NULL == regularExpression)
			{
				// LOG_FMT("NULL == targetCharSequence  || NULL == regularExpression \n");
				return false;
			}

			try
			{
				std::string strInput(targetCharSequence);
				std::regex regularExpress(regularExpression);

				if (std::regex_match(strInput, regularExpress))
				{
					return true;
				}
				else
				{
					return false;
				}
			}
			catch (std::exception &e)
			{
				std::cout << __FUNCTION__ << e.what() << std::endl;
				return false;
			}
		}

		TOOL_SDK_API std::vector<int> DLL_SPEC Tool_getAllNumberFromString(const char *srcString)
		{
			std::vector<int> tempVec;
			if (NULL == srcString)
				return tempVec;

			std::string strSrc(srcString);
			for (auto &c : strSrc)
			{
				if (!std::isdigit(c) && !std::isblank(c))
				{
					c = ' ';
				}
			}
			std::stringstream ss;

			/* Storing the whole string into string stream */
			ss << strSrc;

			/* Running loop till the end of the stream */
			int iFound = 0;
			while (!ss.eof())
			{
				if (ss >> iFound)
				{
					tempVec.push_back(iFound);
				}
			}
			return tempVec;
		}

        TOOL_SDK_API std::vector<int> DLL_SPEC Tool_separate_single_number_from_string(const char *numString)
        {
            std::vector<int> numList;

			if (NULL == numString)
				return numList;

			std::string strSrc(numString);
			for (auto &c : strSrc)
			{
				if (std::isdigit(c))
				{
					numList.push_back((int(c) - 48));
				}
			}
			return numList;
        }

        TOOL_SDK_API int DLL_SPEC Tool_CopyStringToBuffer(char *bufer, int bufLen, const char *srcStr)
        {
			if (NULL == bufer || bufLen == 0 || NULL == srcStr || strlen(srcStr) <= 0)
			{
				return -1;
			}
			memset(bufer, '\0', bufLen);
			if (bufLen > strlen(srcStr))
			{
				memcpy(bufer, srcStr, strlen(srcStr));
			}
			else
			{
				memcpy(bufer, srcStr, bufLen - 1);
			}
			return 0;
		}

#ifdef _WIN32
		TOOL_SDK_API std::wstring DLL_SPEC Tool_string2wstring(std::string strSrc)
		{
			std::wstring wstrDst;
			int iWstrLen = MultiByteToWideChar(CP_ACP, 0, strSrc.c_str(), strSrc.size(), NULL, 0);
			wchar_t *pwcharBuf = new wchar_t[iWstrLen + sizeof(wchar_t)]; // 多一个结束符
			if (pwcharBuf == NULL || iWstrLen <= 0)
			{
				return L"";
			}
			memset(pwcharBuf, 0, iWstrLen * sizeof(wchar_t) + sizeof(wchar_t));
			MultiByteToWideChar(CP_ACP, 0, strSrc.c_str(), strSrc.size(), pwcharBuf, iWstrLen);
			pwcharBuf[iWstrLen] = L'\0';
			wstrDst.append(pwcharBuf);
			delete[] pwcharBuf;
			pwcharBuf = NULL;
			return wstrDst;
		}

		TOOL_SDK_API std::string  DLL_SPEC Tool_wstring2string(std::wstring strSrc)
		{
			int len = WideCharToMultiByte(CP_UTF8, 0, strSrc.c_str(), strSrc.size(), NULL, 0, NULL, NULL);
			char *buffer = new char[len + 1];
			memset(buffer, '\0', sizeof(char) * (len + 1));
			WideCharToMultiByte(CP_UTF8, 0, strSrc.c_str(), strSrc.size(), buffer, len, NULL, NULL);
			std::string result(buffer);
			delete[] buffer;
			return result;
		}

#endif

		TOOL_SDK_API bool DLL_SPEC Tool_GetDataAttributFromAppenedInfo(
			const char* pszAppendInfo,
			const char* strItemName,
			const char* strAttributeName,
			char *pszRstBuf,
			int *piRstBufLen)
		{
			const std::string strAppendInfo(pszAppendInfo);
			size_t siStart = strAppendInfo.find(strItemName);
			if (siStart == std::string::npos)
			{
				return false;
			}
			siStart = strAppendInfo.find(strAttributeName, siStart + 1);

			siStart = strAppendInfo.find("\"", siStart + 1);
			if (siStart == std::string::npos)
			{
				return false;
			}
			size_t siEnd = strAppendInfo.find("\"", siStart + 1);
			if (siEnd == std::string::npos)
			{
				return false;
			}

			std::string strRst = strAppendInfo.substr(siStart + 1, siEnd - siStart - 1);
			if (*piRstBufLen < (int)strRst.length())
			{
				*piRstBufLen = (int)strRst.length();
				return false;
			}

			// strncpy_s(pszRstBuf, *piRstBufLen, strRst.c_str(), (int)strRst.length());
			strncpy(pszRstBuf, strRst.c_str(), (int)strRst.length());
			*piRstBufLen = (int)strRst.length();
			return true;
		}

		TOOL_SDK_API bool DLL_SPEC Tool_GetTextNodeFromXML(const char* XmlInfoBuf, const char *NodeName, char *ValueBuf, int bufLength)
		{
			if (NULL == XmlInfoBuf || NodeName == NULL || ValueBuf == NULL || bufLength <= 0)
			{
				return false;
			}
			const char *pNodeName = NodeName;
			std::string strEndNodeName;
			strEndNodeName.append("<");
			strEndNodeName.append("/");
			strEndNodeName.append(pNodeName);

			const std::string strInfo(XmlInfoBuf);

			size_t iPos = strInfo.find(strEndNodeName);
			if (std::string::npos == iPos)
			{
				printf("can not find node %s .\n", strEndNodeName.c_str());
				return false;
			}
			std::string strSubBefore = strInfo.substr(0, iPos);
			size_t iPos2 = strSubBefore.rfind(">");
			if (std::string::npos == iPos)
			{
				printf("can not find text '>' .\n");
				return false;
			}

			std::string strValue = strInfo.substr(iPos2 + 1, iPos - iPos2 - 1);
			// printf("find then node ' %s'  text = '%s'", pNodeName, strValue.c_str());

			if (strValue.length() >= bufLength)
			{
                printf("value length %u is larger than buffer length %u.", strValue.length(), bufLength);
				return false;
			}
			else
			{
				memset(ValueBuf, '\0', bufLength);
				memcpy(ValueBuf, strValue.c_str(), strValue.length());

				return true;
			}
		}

		TOOL_SDK_API std::vector<std::string> DLL_SPEC Tool_SplitStringFromNewLine(const std::string &strBuf)
		{
			std::stringstream ss(strBuf);
			std::vector<std::string> outVector;

			std::string s;
			while (std::getline(ss, s))
			{

				for (std::string::size_type i = 0; i < s.length(); i++)
				{
					if (0X01 == s[i])
					{
						s[i] = 0x20;
					}
				}
				s.erase(std::remove(s.begin(), s.end(), '\r'), s.end());
				s.erase(std::remove(s.begin(), s.end(), '\n'), s.end());
				std::string::size_type iPos = s.find_last_not_of(" ");
				s.erase(iPos + 1);
				// std::cout << "size " << s.length() << "  :"<< s << std::endl;
				outVector.push_back(s);
			}
			return outVector;
		}

		TOOL_SDK_API std::vector<std::string> DLL_SPEC Tool_getStringbyRegexFormat(const std::string &strSource, const std::string &regexFormat)
		{
			std::vector<std::string> vecRet;

			std::regex regexString(regexFormat);
			std::smatch sm;
			std::string strText = strSource;
			while (std::regex_search(strText, sm, regexString))
			{
				vecRet.push_back(sm.str());

				strText = sm.suffix();
			}
			return vecRet;
		}

		TOOL_SDK_API std::string  DLL_SPEC Tool_remove_consecutive_blank_spaces(std::string strInpuf)
		{
			char nextSymbol, prevSymbol = '\n';

			std::string strOut;
			for (std::string::iterator it = strInpuf.begin(); it != strInpuf.end(); it++)
			{
				if (it <= strInpuf.end() - 2)
				{
					prevSymbol = *it;
					nextSymbol = *(it + 1);

					if ((nextSymbol != ' ') || (prevSymbol != ' '))
					{
						strOut.push_back(prevSymbol);
					}
				}
				else
				{
					strOut.push_back(*it);
				}
			}
			return strOut;
		}

		TOOL_SDK_API bool DLL_SPEC Tool_remove_consecutive_spaces(const char* strOrigin, char *finalStringBuf, int bufLen)
		{
			if(NULL == strOrigin || NULL == finalStringBuf || bufLen <= 0)
				return false;
			// n is length of the original string
			std::string str(strOrigin);
			int n = str.length();

			// i points to next position to be filled in
			// output string/ j points to next character
			// in the original string
			int i = 0, j = -1;

			// flag that sets to true is space is found
			bool spaceFound = false;

			// Handles leading spaces
			while (++j < n && str[j] == ' ')
				;

			// read all characters of original string
			while (j < n)
			{
				// if current characters is non-space
				if (str[j] != ' ')
				{
					// remove preceding spaces before dot,
					// comma & question mark
					if ((str[j] == '.' || str[j] == ',' || str[j] == '?') && i - 1 >= 0 && str[i - 1] == ' ')
					{
						str[i - 1] = str[j++];
					}
					else
					{
						// copy current character at index i
						// and increment both i and j
						str[i++] = str[j++];
					}
					// set space flag to false when any
					// non-space character is found
					spaceFound = false;
				}
				// if current character is a space
				else if (str[j++] == ' ')
				{
					// If space is encountered for the first
					// time after a word, put one space in the
					// output and set space flag to true
					if (!spaceFound)
					{
						str[i++] = ' ';
						spaceFound = true;
					}
				}
			}

			// Remove trailing spaces
			if (i <= 1)
				str.erase(str.begin() + i, str.end());
			else
				str.erase(str.begin() + i - 1, str.end());

#ifdef _WIN32
			strncpy_s(finalStringBuf, bufLen, str.c_str(), str.length());
#else
			snprintf(finalStringBuf, bufLen, "%s", str.c_str());
#endif
            return true;
		}


		TOOL_SDK_API bool  DLL_SPEC Tool_Trim(const char* src, char* finalStringBuf, int bufLen)
		{
			 if (NULL == src || NULL == finalStringBuf || bufLen <= 0)
			 {
				 return false;
			 }
			 std::string strFinal(src);
			 strFinal.erase(0, strFinal.find_first_not_of(" "));
			 strFinal.erase(strFinal.find_last_not_of(" ") + 1);

#ifdef _WIN32
             _snprintf(finalStringBuf, bufLen, "%s", strFinal.c_str());
#else
             snprintf(finalStringBuf, bufLen, "%s", strFinal.c_str());
#endif
			 return true;
		}

		TOOL_SDK_API bool  DLL_SPEC Tool_ByteToString(const char* pbData, int iLen, char* finalStringBuf, int bufLen)
		{
			if(NULL == pbData || NULL == finalStringBuf || bufLen <= 0)
			{
				return false;
			}
			std::string strData;
			for (int i = 0; i < iLen; i++)
			{
				char szTmp[8];
				sprintf(szTmp, "%02X", pbData[i]);
				strData.append(szTmp);
			}
#ifdef _WIN32
			_snprintf(finalStringBuf, bufLen, "%s", strData.c_str());
#else
			snprintf(finalStringBuf, bufLen, "%s", strData.c_str());
#endif
			return true;
		}
		TOOL_SDK_API std::string  DLL_SPEC Tool_vecToString(const std::vector<unsigned char>& vec)
		{
			std::string strData;
			for (std::vector<unsigned char>::const_iterator iter = vec.begin(); iter != vec.end(); iter ++)
			{
				char szTmp[8];
				sprintf(szTmp, "%02X",*iter);
				strData.append(szTmp);
			}
			return strData;
		}
	}
}
